using UnityEngine;
using System.Collections;

public enum eHexagorasForms	
{
	Ship,
	Mech,
	Motorbike,
	ShipHighSpeed,
	Mantis,
	Alejandro
}

public class Hexagoras : MonoBehaviour {
	#region Variables
	
		#region States
			public	eHexagorasForms			m_eTransformationCur;
			public	float					m_fTransformTimeTotal	= 0.5f;
			private	float					m_fTransformTimeCur;
		#endregion
		
		#region Sidescroll Movement
			public  Mover2D					m_scSidescrollMover;
			public	SidescrollPlacer		m_spSidescrollPlacer;
			public	Vector2					m_v2InitialRelativePsition;
	
			public	SidescrollMovementData	m_sMovementVarsShip;
			public	SidescrollMovementData	m_sMovementVarsMech;
			
			public	SideScrollExternData	m_sExternalForces;
	    #endregion
	
	    #region  Input
			public	float					m_fInputMin			= 0.15f;	// Minimum norm to be considered
			public	float					m_fInputMed			= 0.5f;		// Medium norm to decide slow or fast
			public	float					m_fInputMax			= 0.8f;		// Maximum norm before considering 1
			public	bool					m_bUseInputCurve	= false;	// decides if the input will be treated with a curve		
	        public  AnimationCurve  		m_cInputTreatment;          	// Curve that transforms the input
			public	bool					m_bInputSlowLock	= false;
			public	float					m_fInputSqrMagToLock= 0.5f;		// Minimum norm to be considered
	    #endregion
	
		#region Combos
				public ComboManager				m_cmComboManager;
		#endregion
	
	    #region Test objects
		    private GameObject      		m_oBullet;
			public	MeshRenderer			m_mMech;
			public	MeshRenderer			m_mShip;
			public	AnimationCurve			m_acDebugCurve;
	    #endregion
	
		#region Time
			private float					m_fTimeCoef;
			private float					m_fDeltaTime;
			//public	float					m_fAnomalyTimeAwarenessPercent		=	1.0f;
			public	bool					m_bAnomalyTimeAwareness				=	true;
		#endregion
	
	#endregion
	
    //---------------------------------------------------------------------------------------------------------
	// This function is called after load, before the function start (ED)
    //---------------------------------------------------------------------------------------------------------
	void Awake()
	{
		m_oBullet	=	GameObject.Find("BasicBullet");
		if(m_oBullet == null)
		{
			Debug.LogError("You need an object named BasicBullet in the map");
		}
		
		m_eTransformationCur 	= 	eHexagorasForms.Ship;
		
		m_mMech.enabled			=	false;
		m_mShip.enabled			=	true;
		
		m_fTimeCoef 			= 	1.0f;
		
		// Init the mover
		m_scSidescrollMover.InitData(m_fInputMed * m_fInputMed, ref m_sMovementVarsShip, ref m_sExternalForces);
		
		// Init the placer
		m_spSidescrollPlacer.UpdateAndPlace(transform, ref m_v2InitialRelativePsition);
		
		// Init the external data controller
		ExternalTimeAndMedController	etmc_Controller = gameObject.GetComponent("ExternalTimeAndMedController") as ExternalTimeAndMedController; 
		etmc_Controller.SetDelegateToChangeMedium(new PassMediumData(ChangeMedium));
		etmc_Controller.SetDelegateToChangeTimeCoef(new PassTimeCoef(ChangeTimeCoef));
	}
	
	#region Updaters
	
    //---------------------------------------------------------------------------------------------------------
    // Update is called once per frame
    //---------------------------------------------------------------------------------------------------------
    void Update()
    {
		// Get the delta time
        //---------------------------------------------------------------------------------------------------------
		m_fDeltaTime	=	Time.deltaTime * m_fTimeCoef;
		
		
		// Transform
        //---------------------------------------------------------------------------------------------------------
		UpdateTransformation();
		
		
		// Weapons
        //---------------------------------------------------------------------------------------------------------
		UpdateFire();   
		
		
		// Movement
        //---------------------------------------------------------------------------------------------------------
        UpdateMovement();
	}
	
    //---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	private void UpdateTransformation()
	{
		if(Input.GetButtonDown("B"))
		{
			switch(m_eTransformationCur)
			{
				case eHexagorasForms.Ship :
					m_scSidescrollMover.SetNewVariables(ref m_sMovementVarsMech, m_fTransformTimeTotal);
					m_eTransformationCur = eHexagorasForms.Mech;
					m_mMech.enabled			=	true;
					m_mShip.enabled			=	false;
				break;
				case eHexagorasForms.Mech :
					m_scSidescrollMover.SetNewVariables(ref m_sMovementVarsShip, m_fTransformTimeTotal);
					m_eTransformationCur 	=	eHexagorasForms.Ship;
					m_mMech.enabled			=	false;
					m_mShip.enabled			=	true;
				break;
			}
		}
	}
	
    //---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	private void UpdateFire()
	{
		if(Input.GetButtonDown("A"))
	    {
		    // Duplicate the bullet and set it on place, oriented (ED)
		    GameObject oInstance = Instantiate(m_oBullet, transform.position, transform.rotation) as GameObject;
			oInstance.transform.Rotate(0,0,-90);
		    
		    oInstance.SendMessage("SetForDestructionOnBecameInvisible");
	    }
		if(Input.GetButtonDown("RB"))
		{
			Vector2 vHitForce = new Vector2(10.0f, 20.0f);
			
			m_scSidescrollMover.Hit(ref vHitForce, 0.5f, false, false);
		}
	}
	
    //---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	private void UpdateMovement()
	{
		// Get and treat the input (ED)
		//---------------------------------------------------------------------------------------------------------
		Vector2 vInput			=	GetInputForMovement();
		
		// Move the ship
        //---------------------------------------------------------------------------------------------------------
		//m_scSidescrollMover.PlaceMe(ref vInput, m_fDeltaTime, transform);
		
		
		// Get the new speed
        //---------------------------------------------------------------------------------------------------------
		Vector2 vDisplacement	=	m_scSidescrollMover.GetNewDisplacement(ref vInput, m_fDeltaTime);
		//m_scSidescrollMover.PlaceMeWorld(ref vInput, m_fDeltaTime, transform);
		
		
		// Move the ship (ED)
        //---------------------------------------------------------------------------------------------------------
        MoveTheShip(ref vDisplacement);
        
	}
	
	#endregion
	
    //---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	private Vector2 GetInputForMovement()
	{
		// Get the raw input (ED)
        //---------------------------------------------------------------------------------------------------------
        Vector2 vInput		= new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
		
		
        // Discard it if too small
        //---------------------------------------------------------------------------------------------------------
		float fInputMagnitude = vInput.sqrMagnitude;
		if(fInputMagnitude < m_fInputMin * m_fInputMin)
		{
			vInput = Vector2.zero;
			fInputMagnitude	= 0.0f;
		}
		
        // If valid, Normalize it to have the same result with keyboard, D_Pad and analog(normalized by construction) (ED)
        //---------------------------------------------------------------------------------------------------------
		else
		{	
			// Check if the maximum input is accepted
        	//---------------------------------------------------------------------------------------------------------
			if(fInputMagnitude > m_fInputMax * m_fInputMax)
			{
				vInput.Normalize();
				fInputMagnitude	= 1.0f;
				
		        // Modify it with a curve(ED)
		        //---------------------------------------------------------------------------------------------------------
				if(m_bUseInputCurve)
				{
			        vInput.x = Mathf.Sign(vInput.x) * m_cInputTreatment.Evaluate(Mathf.Abs(vInput.x));
			        vInput.y = Mathf.Sign(vInput.y) * m_cInputTreatment.Evaluate(Mathf.Abs(vInput.y));
				}
			}
		
			// Transform the input from the camera to the gameplay area
	        //---------------------------------------------------------------------------------------------------------
			// We can abuse the Vector2 to Vector3 automatic conversions (ED)
			vInput		=	Camera.main.transform.right * vInput.x + Camera.main.transform.up * vInput.y;
			if(m_scSidescrollMover.m_sgaGameplayArea)
			{
				vInput.x	=	Vector3.Dot(vInput, m_scSidescrollMover.m_sgaGameplayArea.transform.right);
				vInput.y	=	Vector3.Dot(vInput, m_scSidescrollMover.m_sgaGameplayArea.transform.up);
				
				//vInput	=	m_scSidescrollMover.m_sgaGameplayArea.transform.InverseTransformDirection(vInput);
			}
			// Recover the original magnitude
			vInput 		*=	fInputMagnitude / vInput.magnitude;
		}
			
		// Check for slow lock (ED)
        //---------------------------------------------------------------------------------------------------------
		if(m_bInputSlowLock)
		{
			if(!Input.GetButton("L3"))
			{
				m_bInputSlowLock = false;
				m_scSidescrollMover.SlowLock = m_bInputSlowLock;
			}
		}
		else
		{
			if(Input.GetButton("L3"))
			{
				if(vInput.sqrMagnitude <= m_fInputSqrMagToLock)
				{
					m_bInputSlowLock = true;
					m_scSidescrollMover.SlowLock =m_bInputSlowLock;
				}
			}
		}
		
		return vInput;
	}
	
    //---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	private void MoveTheShip(ref Vector2 _v2Displacement)
	{
		m_spSidescrollPlacer.UpdateAndMove(transform, ref _v2Displacement);
		//transform.position += new Vector3(_v2Displacement.x, _v2Displacement.y, 0.0f);
	}
	
	#region External data
	
    //---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	public void ChangeMedium(ref SideScrollExternData _sedNewMedium)
	{
		m_scSidescrollMover.SetNewExternVariablesNow(ref _sedNewMedium);
	}
	
	//---------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------
	public void ChangeTimeCoef(float _fNewTimeCoef)
	{
		if(m_bAnomalyTimeAwareness)	
		{
			m_fTimeCoef *= _fNewTimeCoef;
		}
		else
		{
			Time.timeScale /= _fNewTimeCoef; 
			m_fTimeCoef *= _fNewTimeCoef;
		}
		/*
		if(m_fAnomalyTimeAwarenessPercent >= 1.0f)	
		{
			m_fTimeCoef *= _fNewTimeCoef;
		}
		else if(m_fAnomalyTimeAwarenessPercent <= 0.0f)
		{
			Time.timeScale /= _fNewTimeCoef; 
			m_fTimeCoef *= _fNewTimeCoef;
		}
		else if (m_fAnomalyTimeAwarenessPercent < 1.0f)
		{
			// NOT WORKING
			// Add the percentage
			if(_fNewTimeCoef < 1.0f)
			{
				Time.timeScale	/= Maths.FloatMap(0.0f, 1.0f, _fNewTimeCoef, 1.0f, m_fAnomalyTimeAwarenessPercent);
				m_fTimeCoef		*= Maths.FloatMap(0.0f, 1.0f, _fNewTimeCoef, 1.0f, 1.0f - m_fAnomalyTimeAwarenessPercent);
			}
			else
			{
				Time.timeScale	/= Maths.FloatMap(0.0f, 1.0f, 1.0f, _fNewTimeCoef, m_fAnomalyTimeAwarenessPercent);
				m_fTimeCoef		*= Maths.FloatMap(0.0f, 1.0f, 1.0f, _fNewTimeCoef, 1.0f - m_fAnomalyTimeAwarenessPercent);
			}
		}
		*/
	}
	
	#endregion
}